package cn.sfrog.project.biz.applet.utils;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
/**
 * @Author chenl
 * @Date 2023-12-25 10:25
 * @title ApiEncryptUtil
 * @description
 **/

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;

import java.util.*;

@Slf4j
public class ApiEncryptUtil {

    //时间字段（用于限制验签有效时间的开始）
    private static final String TIMESTAMP = "timestamp";
    //签名字段
    private static final String SIGN = "sign";
    //验签秘钥
    private static final String SIGNKEYCODE = "signKey";
    //验签有效时长
    private static final long TSDIFF = 3600000;


    /**
     * 生成签名
     * @param map	请求参数
     * @param signKey	密钥
     * @return
     */
    public static String generateSign(Map<String,Object> map, String signKey) throws Exception {
        String timestamp = null;
        if (map.get(TIMESTAMP) != null){
            timestamp = map.get(TIMESTAMP).toString();
        }
        if (StringUtils.isEmpty(timestamp)) {
            throw new Exception("参数[timestamp]为空");
        }
        // 自然排序后拼接参数值
        String signString = map2SignString(map,signKey);
        // 生成签名
        return DigestUtils.md5Hex(signString);
    }

    public static String generateSign(Map<String,Object> map, String signKey,String signKeyCode) throws Exception {
        // 自然排序后拼接参数值
        String signString = map2SignString(map,signKey,signKeyCode);
        // 生成签名
        if (StringUtils.isNotBlank(signString)){
            String s = DigestUtils.md5Hex(signString);
            return s.toUpperCase();
        }
        return signString;
    }

    /**
     * 校验签名
     * @param map	请求参数
     * @param signKey	密钥
     * @return true/false
     */
    public static boolean checkSign(Map<String,Object> map,String signKey) throws Exception {
        String sign = null;
        if (map.get(SIGN) != null){
            sign = map.get(SIGN).toString();
        }
        String timestamp = null;
        if (map.get(TIMESTAMP) != null){
            timestamp = map.get(TIMESTAMP).toString();
        }
        if (StringUtils.isEmpty(sign) || StringUtils.isEmpty(timestamp)) {
            throw new Exception("请求参数不全sign和timestamp必须要有");
        }
        if (!checkTimestamp(timestamp)) {
            throw new Exception("时间戳无效已过期");
        }
        String newSign = generateSign(map, signKey);
        if (!sign.equals(newSign)) {
            throw new Exception("签名无效");
        }
        return true;
    }

    private static String map2SignString(Map map,String signKey) {
        return map2SignString(map,signKey,SIGNKEYCODE);
    }

    private static String map2SignString(Map map,String signKey,String signKeyCode) {
        if(MapUtils.isEmpty(map)){
            return null ;
        }
        Map<String, Object> paramMap = sortByKey(JSONObject.parseObject(JSONObject.toJSONString(map)));
        StringBuilder content = new StringBuilder();
        for (String key : paramMap.keySet()) {
            if (key.equals(SIGN)) {
                continue;
            }
            String value = null;
            Object o = paramMap.get(key);
            if (o != null){
                value = o.toString();
            }
            // 参数值为空，则不参与签名
            if (StringUtils.isNotBlank(value)) {
                content.append(key).append("=").append(value.trim()).append("&");
            }
        }
        content.append(signKeyCode + "=" + signKey);
        return content.toString();
    }

    private static Map<String, Object> sortByKey(Map map) {
        if(MapUtils.isEmpty(map)){
            return null;
        }
        Map<String, Object> sortMap = new TreeMap<>(Comparator.naturalOrder());
        sortMap.putAll(map);
        for (Map.Entry<String, Object> entry : sortMap.entrySet()) {
            if (entry.getValue() instanceof List){
                List newValues = new ArrayList();
                List values = (List)entry.getValue();
                for (Object value : values) {
                    if (value instanceof Map){
                        Map<String, Object> sortMap1 = sortByKey((JSONObject) JSONObject.toJSON(value));
                        newValues.add(sortMap1);
                    }else {
                        newValues.add(value);
                    }
                }
                entry.setValue(newValues);
            }else if (entry.getValue() instanceof Map){
                Map<String, Object> sortMap1 = sortByKey((JSONObject)JSONObject.toJSON(entry.getValue()));
                entry.setValue(sortMap1);
            }
        }
        return sortMap;
    }

    /**
     * 判断时间戳是否有效 超过阈值TS_DIFF则请求无效
     * @param timestamp
     * @return true/false
     */
    private static boolean checkTimestamp(String timestamp) {
        long curTime = System.currentTimeMillis();
        long dt = curTime - Long.parseLong(timestamp);
        return dt <= TSDIFF;
    }

}


